package com.hu.bgp.server;

import java.io.File;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Observable;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.codec.binary.Base64;

import com.hu.bgp.exceptions.BgpServerException;
import com.hu.bgp.framework.GameStateListener;
import com.hu.bgp.framework.ServerFacade;
import com.hu.bgp.framework.ServerFacade.GameState;
import com.hu.bgp.framework.clientapi.ClientToServerMessage;

import de.novanic.eventservice.client.event.domain.DomainFactory;

/**
 * Een gametype wordt aangemaakt door de BarLoader en bevat alle informatie over
 * lopende games en hoe een nieuwe game te starten.
 * 
 * deze class word iets te vol en moet opgespilts gaan worden!
 * @author ejvos
 */
public class GameType
{
    private GameServerContext gsc;
    private File barArchive;
    private File barExtractDir;
    private Class<?> serverClass;
    private String alias;
    private String displayName;
    private String description;
    private boolean isActive = false;
    
    private GameStateListener gsListener = new GameListener();
	private GameInstanceCollection gameInstances = new GameInstanceCollection();

    public GameType(GameServerContext gsc, File barArchive, File barExtractDir, Class<?> serverClass, String alias, String displayName, String description)
    {
            this.gsc = gsc;
            this.barArchive = barArchive;
            this.barExtractDir = barExtractDir;
            this.serverClass = serverClass;
            this.alias = alias;
            this.displayName = displayName;
            this.description = description;
    }

    public File getBarArchive()
    {
            return barArchive;
    }

    public File getBarExtractDir()
    {
            return barExtractDir;
    }

    public Class<?> getServerClass()
    {
            return serverClass;
    }

    public String getAlias()
    {
            return alias;
    }

    public String getDisplayName()
    {
            return displayName;
    }

    public String getDescription()
    {
            return description;
    }

    public boolean isActive()
    {
            return isActive;
    }

    public void activate()
    {
            isActive = true;
    }

    public void deactivate()
    {
            // TODO
            // kill all instances
            // release resources
    		isActive = false;
    }
    public ServerFacade getGameById(String gameID)
    {
    	return gameInstances.get(gameID);
    }
	public Set<String> getRunningGames()
	{
		return gameInstances.getAllinstances(GameState.running);
	}
	
	//TODO No UUID 
	public ServerFacade initGameInstance()
	{
		ServerFacade game = null;
		GameContext gameContext =  new GameContext(DomainFactory.getDomain(UUID.randomUUID().toString()));
		if (serverClass != null)
		{
			try
			{
				game = (ServerFacade) serverClass.getConstructor(GameContext.class).newInstance(gameContext);
			}
			catch (Throwable e)
			{
				System.out.println("could not instantiate game");
			}
		}
		game.addGameStateListener(gsListener);
		//TODO Degug remove this
		game.setGUID(createGameID(game));
		gameInstances.put(game,game.getGameState());
		return game;
	}
	/*
	 * ID is base64 encoded  hashcode (which is a final method in the Server class)
	 * the '=' placeholders for values that are not multiple of 4 are removed
	 */
	private String createGameID(ServerFacade game)
	{
		return new String(Base64.encodeBase64(intToByteArray(game.hashCode()))).replace('=', ' ').trim();
	}
	public static byte[] intToByteArray(int value) {
        byte[] b = new byte[4];
        for (int i = 0; i < 4; i++) {
            int offset = (b.length - 1 - i) * 8;
            b[i] = (byte) ((value >>> offset) & 0xFF);
        }
        return b;
    }
	
	class GameListener implements GameStateListener{

		public void update(ServerFacade gameServer, GameState state) {
			gameInstances.changeState(gameServer.getGUID(), state);
		}

		public void update(Observable o, Object arg) {
			if(o instanceof ServerFacade && arg instanceof GameState)
				update(o, arg);
			
		}
		
	}
}
